package org.trinity.netdisk.util;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.auth0.jwt.interfaces.JWTVerifier;
import org.trinity.netdisk.entity.Role;
import org.trinity.netdisk.entity.User;
import org.trinity.netdisk.entity.UserFile;
import org.trinity.netdisk.exception.user.NoTokenException;

import javax.servlet.http.HttpServletRequest;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * author: Liao
 */
public class JWTUtil {
    //登录token过期时间 100天
    public static final long LOGIN_EXPIRE_TIME = 24 * 60 * 60 * 100000L;
    //文件token过期时间 1个小时
    public static final long FILE_EXPIRE_TIME = 5 * 60 * 60 * 1000;
    //盐
    private static final String TOKEN_SECRET = "netdisk";

    private static final Algorithm ALGORITHM;

    static {
        ALGORITHM = Algorithm.HMAC256(TOKEN_SECRET);
    }


    public static String sign(Map<String, Object> map, Long expireTime) {
        try {
            // 设置过期时间
            Date date = new Date(System.currentTimeMillis() + expireTime);
            // 私钥和加密算法
            Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET);
            // 设置头部信息
            Map<String, Object> header = new HashMap<>(2);
            header.put("typ", "jwt");
            // 返回token字符串
            JWTCreator.Builder builder = JWT.create()
                    .withHeader(header)
                    .withIssuedAt(new Date()) //发证时间
                    .withExpiresAt(date);  //过期时间

            map.forEach((key, value) -> {
                if (value instanceof Integer) {
                    builder.withClaim(key, (Integer) value);
                } else if (value instanceof Long) {
                    builder.withClaim(key, (Long) value);
                } else if (value instanceof Boolean) {
                    builder.withClaim(key, (Boolean) value);
                } else if (value instanceof String) {
                    builder.withClaim(key, String.valueOf(value));
                } else if (value instanceof Double) {
                    builder.withClaim(key, (Double) value);
                } else if (value instanceof Date) {
                    builder.withClaim(key, (Date) value);
                }
            });
            return builder.sign(algorithm);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static String sign(UserFile userFile){
        try {
            // 设置过期时间
            Date date = new Date(System.currentTimeMillis() + FILE_EXPIRE_TIME);
            // 私钥和加密算法
            Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET);
            // 设置头部信息
            Map<String, Object> header = new HashMap<>(2);
            header.put("typ", "jwt");
            // 返回token字符串
            JWTCreator.Builder builder = JWT.create()
                    .withHeader(header)
                    .withIssuedAt(new Date()) //发证时间
                    .withExpiresAt(date);  //过期时间
            builder.withClaim("id", userFile.getId());
            builder.withClaim("userId", userFile.getUserId());
            return builder.sign(algorithm);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static String sign(User user) {
        try {
            // 设置过期时间
            Date date = new Date(System.currentTimeMillis() + LOGIN_EXPIRE_TIME);
            // 私钥和加密算法
            Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET);
            // 设置头部信息
            Map<String, Object> header = new HashMap<>(2);
            header.put("typ", "jwt");
            // 返回token字符串
            JWTCreator.Builder builder = JWT.create()
                    .withHeader(header)
                    .withIssuedAt(new Date()) //发证时间
                    .withExpiresAt(date);  //过期时间
            builder.withClaim("id", user.getId());
            builder.withClaim("username", user.getUserName());
            builder.withClaim("phone", user.getPhone());
            builder.withClaim("email", user.getEmail());
            builder.withClaim("roleName", user.getRole().getRoleName());
            builder.withClaim("roleDesc", user.getRole().getRoleDesc());
            builder.withClaim("diskSize", user.getRole().getDiskSize());
            builder.withClaim("downloadLimit", user.getRole().getDownloadLimit());
            builder.withClaim("status", user.getStatus());
            return builder.sign(algorithm);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     *
     * @param user 用户对象
     * @param expireTime 毫秒
     * @return token
     */
    public static String sign(User user, Long expireTime) {
        try {
            // 设置过期时间
            Date date = new Date(System.currentTimeMillis() + expireTime);
            // 私钥和加密算法
            Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET);
            // 设置头部信息
            Map<String, Object> header = new HashMap<>(2);
            header.put("typ", "jwt");
            // 返回token字符串
            JWTCreator.Builder builder = JWT.create()
                    .withHeader(header)
                    .withIssuedAt(new Date()) //发证时间
                    .withExpiresAt(date);  //过期时间
            builder.withClaim("id", user.getId());
            builder.withClaim("username", user.getUserName());
            builder.withClaim("phone", user.getPhone());
            builder.withClaim("email", user.getEmail());
            builder.withClaim("roleName", user.getRole().getRoleName());
            builder.withClaim("roleDesc", user.getRole().getRoleDesc());
            builder.withClaim("diskSize", user.getRole().getDiskSize());
            builder.withClaim("downloadLimit", user.getRole().getDownloadLimit());
            builder.withClaim("status", user.getStatus());
            return builder.sign(algorithm);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    public static boolean verify(String token) {
        try {
            if (token == null) {
                return false;
            }
            JWTVerifier verifier = JWT.require(ALGORITHM).build();
            verifier.verify(token);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    public static <T> T getValue(String token, String key, Class<T> clazz) {
        JWTVerifier jwtVerifier = JWT.require(ALGORITHM).build();
        DecodedJWT decodedJWT = jwtVerifier.verify(token);
        return decodedJWT.getClaim(key).as(clazz);
    }

    public static User getUserVale(String token) {
        User user = new User();
        Role role = new Role();
        user.setId(JWTUtil.getValue(token, "id", Long.class));
        user.setUserName(JWTUtil.getValue(token, "username", String.class));
        user.setPhone(JWTUtil.getValue(token, "phone", String.class));
        user.setEmail(JWTUtil.getValue(token, "email", String.class));
        user.setStatus(JWTUtil.getValue(token, "status", Boolean.class));
        role.setRoleName(JWTUtil.getValue(token, "roleName", String.class));
        role.setRoleDesc(JWTUtil.getValue(token, "roleDesc", String.class));
        role.setDiskSize(JWTUtil.getValue(token, "diskSize", Long.class));
        role.setDownloadLimit(JWTUtil.getValue(token, "downloadLimit", Integer.class));
        user.setRole(role);
        return user;
    }

    public static Long getUserId(HttpServletRequest request) {
        String token = request.getHeader("token");
        if(token == null || "".equals(token)){
            throw new NoTokenException();
        }
        return JWTUtil.getValue(token, "id", Long.class);
    }

    public static void main(String[] args) {
        System.out.println(verify("eyJ0eXAiOiJqd3QiLCJhbGciOiJIUzI1NiJ9.eyJpZCI6MSwiZXhwIjoxNjA5MzEwMDkyLCJpYXQiOjE2MDkyMjM2OTIsInVzZXJuYW1lIjoidHJpbml0eSJ9.EN7oP7rL0_MNd_fpTdu6RdB0dIVhMv3XNOYGYbR0fps"));
    }
}